package com.etone.smartAudit.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.etone.smartAudit.domain.*;
import com.etone.smartAudit.dto.DataMetaTask.DataMetaTaskDTO;
import com.etone.smartAudit.dto.dataMeta.DataMetaConfDTO;
import com.etone.smartAudit.dto.dataMeta.FileInfoDTO;
import com.etone.smartAudit.dto.task.DataMetaTaskForTaskDTO;
import com.etone.smartAudit.enums.*;
import com.etone.smartAudit.error.CustomParameterizedException;
import com.etone.smartAudit.mapper.DataMetaConfMapper;
import com.etone.smartAudit.mapper.DataMetaTaskMapper;
import com.etone.smartAudit.mapstruct.DataMetaTaskMapstruct;
import com.etone.smartAudit.utils.BooleanUtil;
import com.etone.smartAudit.utils.StringUtil;
import com.etone.smartAudit.vo.FileVO;
import com.etone.smartAudit.vo.PagerVO;
import com.etone.smartAudit.vo.accountInfo.AccountInfoVO;
import com.etone.smartAudit.vo.dataMetaTask.DataMetaTaskConfDetailVO;
import com.etone.smartAudit.vo.dataMetaTask.DataMetaTaskConfListVO;
import com.etone.smartAudit.vo.dataMetaTask.DataMetaTaskDetailVO;
import com.etone.smartAudit.vo.dataMetaTask.DataMetaTaskListVO;
import com.etone.smartAudit.vo.dataModel.DataModelDetailVO;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * @author: sovy
 * @date: 2020/11/23
 * @description:
 */

@Log4j2
@Service
public class DataMetaTaskService extends ServiceImpl<DataMetaTaskMapper, DataMetaTask> {

    @Autowired
    private DataMetaTaskMapstruct dataMetaTaskMapstruct;

    @Autowired
    private AccountInfoService accountInfoService;

    @Autowired
    private DataModelService dataModelService;

    @Autowired
    private FileUploadService fileUploadService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private DataMetaConfMapper dataMetaConfMapper;

    @Value("${server.servlet.context-path}")
    private String contextPath;

    /**
     * 数据入库
     *
     * @param admin
     * @param dataMetaTaskDTO
     */
    public void add(Admin admin, DataMetaTaskDTO dataMetaTaskDTO) {

        if (CollectionUtils.isEmpty(dataMetaTaskDTO.getFieldInfo())) {
            throw new CustomParameterizedException("字段信息不能为空");
        }

        //数据模型
        DataModel dataModel = dataModelService.get(dataMetaTaskDTO.getDataModeId());

        //文件实际相对路径
        String relativePath = null;
        if (dataMetaTaskDTO.getFile() != null) {
            String path = dataMetaTaskDTO.getFile().getUrl();
            String contextPath_pre = contextPath + "/upload/files";
            if (path.startsWith(contextPath_pre)) {
                relativePath = path.substring(contextPath_pre.length());
                if (!relativePath.startsWith("/")) {
                    relativePath = "/" + relativePath;
                }
            }
        }

        //账号信息
        AccountInfoVO accountInfoVO = accountInfoService.get(dataModel.getServerId(), dataModel.getItemId(), AccountType.valueOf(dataModel.getDataBaseType().name()), dataModel.getDataBaseType().equals(DataBaseType.GREENPLUM) ? true : null);
        if (accountInfoVO == null) {
            throw new CustomParameterizedException("没有相关资源账号信息");
        }
        DataMetaTask dataMetaTask = DataMetaTask
                .builder()
                .serverId(dataModel.getServerId())
                .serverIp(dataModel.getServerIp())
                .serverName(dataModel.getServerName())
                .databaseType(dataModel.getDataBaseType())
                .databaseName(dataModel.getDatabaseName())
                .schemaName(dataModel.getSchemaName())
                .tableName(dataModel.getEnTableName())
                .databaseUser(accountInfoVO.getAccount())
                .databasePassword(accountInfoVO.getPassword())
                .databasePort(accountInfoVO.getPort())
                .createAdminId(admin.getId())
                .createAdminName(admin.getNickName())
                .createTime(new Date())
                .relativePath(relativePath)
                .state(dataMetaTaskDTO.getIsAuto() ? CheckState.EXECUTE_NOT_START : CheckState.CHECKING)
                .build();
        dataMetaTaskMapstruct.copy2DataMetaTask(dataMetaTask, dataMetaTaskDTO);
        save(dataMetaTask);

        //人工入库添加到任务列表
        if (BooleanUtil.isFalse(dataMetaTaskDTO.getIsAuto())) {
            DataMetaTaskForTaskDTO dataMetaTaskForTaskDTO = dataMetaTaskMapstruct.getDataMetaTaskForTaskDTO(dataMetaTask);
            dataMetaTaskForTaskDTO.setItemId(dataModel.getItemId());
            dataMetaTaskForTaskDTO.setItemName(dataModel.getItemName());
            dataMetaTaskForTaskDTO.setItemTypeId(dataMetaTask.getId());
            dataMetaTaskForTaskDTO.setDataModeCnTableName(dataModel.getCnTableName());
            dataMetaTaskForTaskDTO.setDataModeEnTableName(dataModel.getEnTableName());
            taskService.add(dataMetaTaskForTaskDTO, admin, TaskType.MAN_MADE_STORAGE);
        }

        //清理文件
        fileUploadService.deleteFileByFileDTO(Arrays.asList(dataMetaTaskDTO.getFile()), false, true);
    }

    /**
     * 编辑
     *
     * @param admin
     * @param id
     * @param dataMetaTaskDTO
     */
    @Transactional(rollbackFor = Exception.class)
    public void edit(Admin admin, Integer id, DataMetaTaskDTO dataMetaTaskDTO) {
        DataMetaTask dataMetaTask = get(id);

        //是否无法编辑
        Boolean isNotArrowEdit = !CheckState.isArrowEdit(dataMetaTask.getState());
        if (BooleanUtil.isTrue(isNotArrowEdit)) {
            throw new CustomParameterizedException("该状态无法编辑");
        }

        //旧文件
        FileVO oldFile = dataMetaTask.getFile();

        //数据模型
        DataModel dataModel = dataModelService.get(dataMetaTaskDTO.getDataModeId());

        //文件实际相对路径
        String relativePath = null;
        if (dataMetaTaskDTO.getFile() != null) {
            String path = dataMetaTaskDTO.getFile().getUrl();
            String contextPath_pre = contextPath + "/upload/files";
            if (path.startsWith(contextPath_pre)) {
                relativePath = path.substring(contextPath_pre.length());
                if (!relativePath.startsWith("/")) {
                    relativePath = "/" + relativePath;
                }
            }
        }

        //账号信息
        AccountInfoVO accountInfoVO = accountInfoService.get(dataModel.getServerId(), dataModel.getItemId(), AccountType.valueOf(dataModel.getDataBaseType().name()), dataModel.getDataBaseType().equals(DataBaseType.GREENPLUM) ? true : null);
        if (accountInfoVO == null) {
            throw new CustomParameterizedException("没有相关资源账号信息");
        }
        dataMetaTask.setServerId(dataModel.getServerId());
        dataMetaTask.setServerIp(dataModel.getServerIp());
        dataMetaTask.setServerName(dataModel.getServerName());
        dataMetaTask.setDatabaseName(dataModel.getDatabaseName());
        dataMetaTask.setDatabaseType(dataModel.getDataBaseType());
        dataMetaTask.setSchemaName(dataModel.getSchemaName());
        dataMetaTask.setTableName(dataModel.getEnTableName());
        dataMetaTask.setDatabaseUser(accountInfoVO.getAccount());
        dataMetaTask.setDatabasePassword(accountInfoVO.getPassword());
        dataMetaTask.setDatabasePort(accountInfoVO.getPort());
        dataMetaTask.setRelativePath(relativePath);
        dataMetaTask.setState(dataMetaTask.getIsAuto() ? CheckState.EXECUTE_NOT_START : CheckState.CHECKING);

        dataMetaTaskMapstruct.copy2DataMetaTask(dataMetaTask, dataMetaTaskDTO);
        updateById(dataMetaTask);

        if (BooleanUtil.isFalse(dataMetaTaskDTO.getIsAuto())) {
            /**
             * 获取任务
             */
            Task task = taskService.get(id, TaskType.MAN_MADE_STORAGE);

            DataMetaTaskForTaskDTO dataMetaTaskForTaskDTO = dataMetaTaskMapstruct.getDataMetaTaskForTaskDTO(dataMetaTask);
            taskService.edit(task.getId(), dataMetaTaskForTaskDTO, admin, TaskType.MAN_MADE_STORAGE);
        }

        //清理文件
        fileUploadService.deleteFileForUpdate(Arrays.asList(dataMetaTaskDTO.getFile()), Arrays.asList(oldFile));
    }

    public DataMetaTask get(Integer id) {
        DataMetaTask dataMetaTask = getById(id);
        if (dataMetaTask == null) {
            throw new CustomParameterizedException("入库单不存在");
        }
        return dataMetaTask;
    }

    /**
     * 人工入库审核结果
     *
     * @param id         人工入库id
     * @param checkState 审核结果
     * @param result     结果说明
     * @param admin      审核人
     */
    public void auditResult(Integer id, CheckState checkState, String result, Admin admin) {
        if (checkState.equals(CheckState.EXECUTE_STARTING)) {
            baseMapper.updateCheckState(id, checkState);
        } else {
            baseMapper.auditResult(id, checkState, result, admin.getId(), admin.getNickName());
        }

    }

    /**
     * 入库列表
     *
     * @param admin
     * @param isAuto
     * @param taskName
     * @param startCreateTime
     * @param endCreateTime
     * @param state
     * @param page
     * @param pageSize
     * @return
     */
    public PagerVO<DataMetaTaskListVO> list(Admin admin, Boolean isAuto, String taskName, Date startCreateTime, Date endCreateTime, CheckState state, int page, int pageSize) {

        Page<DataMetaTaskListVO> dataMetaTaskListVOPage = PageHelper.startPage(page, pageSize).doSelectPage(() -> baseMapper.findList(admin.isAdmin() ? null : admin.getId(), isAuto, taskName, startCreateTime, endCreateTime, state));
        return PagerVO.of(dataMetaTaskListVOPage);
    }

    /**
     * 详情
     *
     * @param id
     * @return
     */
    public DataMetaTaskDetailVO detail(Integer id) {
        DataMetaTask dataMetaTask = get(id);
        return dataMetaTaskMapstruct.getDataMetaTaskDetailVO(dataMetaTask);
    }

    /**
     * 自动入库转为人工入库
     *
     * @param admin
     * @param id
     */
    @Transactional(rollbackFor = Exception.class)
    public void auto2Man(Admin admin, Integer id) {
        DataMetaTask dataMetaTask = get(id);
        if (!dataMetaTask.getIsAuto()) {
            throw new CustomParameterizedException("非法操作，已是人工入库");
        }
        if (!dataMetaTask.getState().equals(CheckState.REJECT)) {
            throw new CustomParameterizedException("改状态无法转为人工入库");
        }
        dataMetaTask.setState(CheckState.CHECKING);
        dataMetaTask.setIsAuto(false);
        //更新状态
        updateById(dataMetaTask);

        //获取模型
        DataModel dataModel = dataModelService.get(dataMetaTask.getDataModeId());

        DataMetaTaskForTaskDTO dataMetaTaskForTaskDTO = dataMetaTaskMapstruct.getDataMetaTaskForTaskDTO(dataMetaTask);
        dataMetaTaskForTaskDTO.setItemId(dataModel.getItemId());
        dataMetaTaskForTaskDTO.setItemName(dataModel.getItemName());
        dataMetaTaskForTaskDTO.setItemTypeId(dataMetaTask.getId());
        taskService.add(dataMetaTaskForTaskDTO, admin, TaskType.MAN_MADE_STORAGE);
    }

    public void addDataMetaConf(DataMetaConfDTO dataMetaConfDTO, Admin admin) {
        String fileInfo = JSON.toJSONString(dataMetaConfDTO.getFileInfo());
        DataMetaConf dataMetaConf = new DataMetaConf();
        dataMetaConf.setFileInfo(fileInfo);
        DataModelDetailVO detailVO = dataModelService.detail(dataMetaConfDTO.getModelId(), admin);
        dataMetaConf.setState(UseState.NOT_ONLINE.name());
        dataMetaConf.setLevel1Id(detailVO.getLevel1Id());
        dataMetaConf.setLevel1(detailVO.getLevel1());
        dataMetaConf.setLevel2Id(detailVO.getLevel2Id());
        dataMetaConf.setLevel2(detailVO.getLevel2());
        dataMetaConf.setCreateTime(new Date());
        dataMetaConf.setUpdateTime(new Date());
        dataMetaConf.setCreateAdminId(admin.getId());
        dataMetaConf.setCreateAdmin(admin.getNickName());
        BeanUtils.copyProperties(dataMetaConfDTO,dataMetaConf);

        dataMetaConfMapper.insert(dataMetaConf);
    }

    public PagerVO<DataMetaTaskConfListVO> dataMetaConf(int page, int pageSize, String onlineState, String taskName, String cnTableName, String level2Ids) {
        List<Integer> level2 = StringUtil.intToList(level2Ids);
        Page<DataMetaTaskConfListVO> pageVO = PageHelper.startPage(page, pageSize).doSelectPage(() ->
                dataMetaConfMapper.list(onlineState,taskName,cnTableName,level2));
        return PagerVO.of(pageVO);
    }

    public DataMetaTaskConfDetailVO confDetail(Integer id, Admin admin) {
        DataMetaConf dataMetaConf = dataMetaConfMapper.selectById(id);
        List<FileInfoDTO> fileInfoDTOS = JSONArray.parseArray(dataMetaConf.getFileInfo(), FileInfoDTO.class);
        DataMetaTaskConfDetailVO detailVO = new DataMetaTaskConfDetailVO();
        BeanUtils.copyProperties(dataMetaConf,detailVO);
        detailVO.setFileInfo(fileInfoDTOS);
        detailVO.setDataModelDetailVO(dataModelService.detail(dataMetaConf.getModelId(),admin));
        return detailVO;
    }
}
